/*******************************************************************************
* @Filename      : bsp_flash.c

* @Description   : bsp_flash.c

* @Version       : 1.0.0

* @Date          : 2023.12.2
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "bsp_flash.h"

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Global variables ----------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

/* Exported functions --------------------------------------------------------*/
/*******************************************************************************
* @Name      : BSP_FLASH_Init
* @Purpose   : BSP_FLASH_Init
* @Param     : None
* @Retval    : None
*******************************************************************************/
void BSP_FLASH_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    SPI_InitTypeDef SPI_InitStruct;

    FLASH_CS_SET();
    
    RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);

    GPIO_PinAFConfig(SPIFLASH_MISO_PORT, SPIFLASH_MISO_PIN_SOURCE, SPIFLASH_MISO_PIN_ALT);
    GPIO_PinAFConfig(SPIFLASH_MOSI_PORT, SPIFLASH_MOSI_PIN_SOURCE, SPIFLASH_MOSI_PIN_ALT);
    GPIO_PinAFConfig(SPIFLASH_CLK_PORT,  SPIFLASH_CLK_PIN_SOURCE,  SPIFLASH_CLK_PIN_ALT);

    GPIO_StructInit(&GPIO_InitStruct);
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Pin   = FLASH_CS_PIN;
    GPIO_InitStruct.GPIO_Mode  = FLASH_CS_MODE;
    GPIO_Init(FLASH_CS_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin   = SPIFLASH_MISO_PIN;
    GPIO_InitStruct.GPIO_Mode  = SPIFLASH_MISO_MODE;
    GPIO_Init(SPIFLASH_MISO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin   = SPIFLASH_MOSI_PIN;
    GPIO_InitStruct.GPIO_Mode  = SPIFLASH_MOSI_MODE;
    GPIO_Init(SPIFLASH_MOSI_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.GPIO_Pin   = SPIFLASH_CLK_PIN;
    GPIO_InitStruct.GPIO_Mode  = SPIFLASH_CLK_MODE;
    GPIO_Init(SPIFLASH_CLK_PORT, &GPIO_InitStruct);

    SPI_StructInit(&SPI_InitStruct);
    SPI_InitStruct.SPI_Mode              = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize          = SPI_DataSize_8b;
    SPI_InitStruct.SPI_DataWidth         = 8;
    SPI_InitStruct.SPI_CPOL              = SPI_CPOL_Low;
    SPI_InitStruct.SPI_CPHA              = SPI_CPHA_1Edge;
    SPI_InitStruct.SPI_NSS               = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    SPI_InitStruct.SPI_FirstBit          = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &SPI_InitStruct);

    SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);
    SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);

    SPI_DMACmd(SPI1, DISABLE);
    SPI_Cmd(SPI1, ENABLE);
}

/*******************************************************************************
 * @Name      : BSP_FLASH_WriteByte
 * @Purpose   : BSP_FLASH_WriteByte
 * @Param     : None
 * @Retval    : None
 *******************************************************************************/
uint32_t BSP_FLASH_WriteByte(uint8_t data)
{
    SPI_SendData(SPI1, data);

    while (1) 
    {
        if(SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT)) {
            break;
        }
    }
    while (1)
    {
        if (SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
        {
            return SPI_ReceiveData(SPI1);
        }
    }
}

/**
    zhao add
    **/

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_RxData_Polling(uint8_t *Buffer, uint8_t Length)
{
    uint8_t i = 0, Data = 0;

    for (i = 0; i < Length; i++)
    {
        SPI_SendData(SPI1, Data);

        while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
        {
        }

        while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
        {
        }

        Buffer[i] = SPI_ReceiveData(SPI1);
    }
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_TxData_Polling(uint8_t *Buffer, uint8_t Length)
{
    uint8_t i = 0;

    for (i = 0; i < Length; i++)
    {
        SPI_SendData(SPI1, Buffer[i]);

        while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT))
        {
        }

        while (RESET == SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL))
        {
        }

        SPI_ReceiveData(SPI1);
    }
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_RxBuffer(uint8_t *Buffer, uint8_t Length)
{
    if (Length)
    {
        SPI_RxData_Polling(Buffer, Length);
    }
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_TxBuffer(uint8_t *Buffer, uint8_t Length)
{
    if (Length)
    {
        SPI_TxData_Polling(Buffer, Length);
    }
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_ReadDeviceID(void)
{
    uint8_t  Command[4] =
    {
        0x90, 0xFF, 0xFF, 0x00
    };
    uint8_t  Buffer[2];
    uint16_t DeviceID = 0;

    FLASH_CS_CLR();

    SPI_FLASH_TxBuffer(Command, 0x04);
    SPI_FLASH_RxBuffer(Buffer, 0x02);

    FLASH_CS_SET();

    DeviceID   = Buffer[0];
    DeviceID <<= 8;
    DeviceID  |= Buffer[1];

    printf("\r\nSPI Flash DeviceID : 0x%04x", DeviceID);
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_ReadJEDEC_ID(void)
{
    uint8_t  Command = 0x9F;
    uint8_t  Buffer[3];
    uint32_t JEDEC_ID = 0;

    FLASH_CS_CLR();
    SPI_FLASH_TxBuffer(&Command, 0x01);
    SPI_FLASH_RxBuffer(Buffer, 0x03);
    FLASH_CS_SET();

    JEDEC_ID   = Buffer[0];
    JEDEC_ID <<= 8;
    JEDEC_ID  |= Buffer[1];
    JEDEC_ID <<= 8;
    JEDEC_ID  |= Buffer[2];

    printf("\r\nSPI Flash JEDEC ID : 0x%06x", JEDEC_ID);
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_WaitBusy(void)
{
    uint8_t  Status     = 0;
    uint8_t  Command[2] =
    {
        0x05, 0xFF
    };
    uint32_t Timeout = 0;

    do
    {
        FLASH_CS_CLR();
        SPI_FLASH_TxBuffer(Command, 0x02);
        SPI_FLASH_RxBuffer(&Status, 0x01);
        FLASH_CS_SET();

        if (Timeout++ > 0xFFFF)
        {
            break;
        }
    }
    while (Status & 0x01);
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_WriteEnable(void)
{
    uint8_t Command = 0x06;

    FLASH_CS_CLR();
    SPI_FLASH_TxBuffer(&Command, 0x01);
    FLASH_CS_SET();
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_SectorErase(uint16_t Index)
{
    uint8_t  Command[4] =
    {
        0x20, 0x00, 0x00, 0x00
    };
    uint32_t Address = Index * 4 * 1024;

    Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
    Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
    Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);

    SPI_FLASH_WriteEnable();

    FLASH_CS_CLR();
    SPI_FLASH_TxBuffer(Command, 4);
    FLASH_CS_SET();

    SPI_FLASH_WaitBusy();
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_FastRead(uint32_t Address, uint8_t *Buffer, uint32_t Length)
{
    uint8_t Command[5] =
    {
        0x0B, 0x00, 0x00, 0x00, 0xFF
    };

    Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
    Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
    Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);

    FLASH_CS_CLR();
    SPI_FLASH_TxBuffer(Command, 0x05);
    SPI_FLASH_RxBuffer(Buffer, Length);
    FLASH_CS_SET();
}

/***********************************************************************************************************************
  * @brief
  * @note   none
  * @param  none
  * @retval none
  *********************************************************************************************************************/
void SPI_FLASH_PageProgram(uint32_t Address, uint8_t *Buffer, uint32_t Length)
{
    uint8_t Command[4] =
    {
        0x02, 0x00, 0x00, 0x00
    };

    Command[1] = (uint8_t)((Address >> 16) & 0x000000FF);
    Command[2] = (uint8_t)((Address >> 8) & 0x000000FF);
    Command[3] = (uint8_t)((Address >> 0) & 0x000000FF);

    SPI_FLASH_WriteEnable();

    FLASH_CS_CLR();
    SPI_FLASH_TxBuffer(Command, 0x04);
    SPI_FLASH_TxBuffer(Buffer, Length);
    FLASH_CS_SET();

    SPI_FLASH_WaitBusy();
}

/* Overrride functions -------------------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

/* End of File ---------------------------------------------------------------*/
